﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management;
using System.Text;
using WMI.NET.Abstracts;
using WMI.NET.CIM;

namespace WMI.NET.ComputerSystemHardware.MassStorage
{
    /// <summary>
    /// The Win32_DiskDrive WMI class represents a physical disk drive as seen by a computer running the Windows operating system. Any interface to a Windows physical disk drive is a descendent (or member) of this class. The features of the disk drive seen through this object correspond to the logical and management characteristics of the drive. In some cases, this may not reflect the actual physical characteristics of the device. Any object based on another logical device would not be a member of this class.
    /// </summary>
    public class Win32_DiskDrive : CIM_DiskDrive
    {

        private Nullable<UInt32> _BytesPerSector;
        private string _FirmwareRevision;
        private Nullable<UInt32> _Index;
        private string _InterfaceType;
        private string _Manufacturer;
        private Nullable<Boolean> _MediaLoaded;
        private string _MediaType;
        private string _Model;
        private Nullable<UInt32> _Partitions;
        private Nullable<UInt32> _SCSIBus;
        private Nullable<UInt16> _SCSILogicalUnit;
        private Nullable<UInt16> _SCSIPort;
        private Nullable<UInt16> _SCSITargetId;
        private Nullable<UInt32> _SectorsPerTrack;
        private string _SerialNumber;
        private Nullable<UInt32> _Signature;
        private Nullable<UInt64> _Size;
        private Nullable<UInt64> _TotalCylinders;
        private Nullable<UInt32> _TotalHeads;
        private Nullable<UInt64> _TotalSectors;
        private Nullable<UInt64> _TotalTracks;
        private Nullable<UInt32> _TracksPerCylinder;

        /// <summary>
        /// Number of bytes in each sector for the physical disk drive.
        /// Example: 512
        /// </summary>
        public Nullable<UInt32> BytesPerSector { get { return _BytesPerSector; } }

        /// <summary>
        /// Revision for the disk drive firmware that is assigned by the manufacturer.
        /// Windows Server 2003 and Windows XP:  This property is not available. 
        /// </summary>
        public string FirmwareRevision { get { return _FirmwareRevision; } }

        /// <summary>
        /// Physical drive number of the given drive. This property is filled by the GetDriveMapInfo method. A value of 0xFF indicates that the given drive does not map to a physical drive.
        /// Example: 1
        /// </summary>
        public Nullable<UInt32> Index { get { return _Index; } }

        /// <summary>
        /// Interface type of physical disk drive. 
        /// </summary>
        public string InterfaceType { get { return _InterfaceType; } } //TODO Enum

        /// <summary>
        /// Name of the disk drive manufacturer.
        /// Example: "Seagate"
        /// </summary>
        public string Manufacturer { get { return _Manufacturer; } }

        /// <summary>
        /// If True, the media for a disk drive is loaded, which means that the device has a readable file system and is accessible. For fixed disk drives, this property will always be TRUE.
        /// </summary>
        public Nullable<Boolean> MediaLoaded { get { return _MediaLoaded; } }

        /// <summary>
        /// Type of media used or accessed by this device. 
        /// </summary>
        public string MediaType { get { return _MediaType; } } //TODO Enum maybe

        /// <summary>
        /// Manufacturer's model number of the disk drive.
        /// Example: "ST32171W"
        /// </summary>
        public string Model { get { return _Model; } }

        /// <summary>
        /// Number of partitions on this physical disk drive that are recognized by the operating system.
        /// Example: 2
        /// </summary>
        public Nullable<UInt32> Partitions { get { return _Partitions; } }

        /// <summary>
        /// SCSI bus number of the disk drive.
        /// Example: 0
        /// </summary>
        public Nullable<UInt32> SCSIBus { get { return _SCSIBus; } }

        /// <summary>
        /// SCSI logical unit number (LUN) of the disk drive.
        /// Example: 0
        /// </summary>
        public Nullable<UInt16> SCSILogicalUnit { get { return _SCSILogicalUnit; } }

        /// <summary>
        /// SCSI port number of the disk drive.
        /// Example: 0
        /// </summary>
        public Nullable<UInt16> SCSIPort { get { return _SCSIPort; } }

        /// <summary>
        /// SCSI identifier number of the disk drive.
        /// Example: 0
        /// </summary>
        public Nullable<UInt16> SCSITargetId { get { return _SCSITargetId; } }

        /// <summary>
        /// Number of sectors in each track for this physical disk drive.
        /// Example: 63
        /// </summary>
        public Nullable<UInt32> SectorsPerTrack { get { return _SectorsPerTrack; } }

        /// <summary>
        /// Number allocated by the manufacturer to identify the physical media.
        /// Example: WD-WM3493798728
        /// Windows Server 2003 and Windows XP:  This property is not available. 
        /// </summary>
        public string SerialNumber { get { return _SerialNumber; } }

        /// <summary>
        /// Disk identification. This property can be used to identify a shared resource. This property has been added for Windows XP.
        /// </summary>
        public Nullable<UInt32> Signature { get { return _Signature; } }

        /// <summary>
        /// Size of the disk drive. It is calculated by multiplying the total number of cylinders, tracks in each cylinder, sectors in each track, and bytes in each sector.
        /// </summary>
        public Nullable<UInt64> Size { get { return _Size; } }

        /// <summary>
        /// Total number of cylinders on the physical disk drive. Note: the value for this property is obtained through extended functions of BIOS interrupt 13h. The value may be inaccurate if the drive uses a translation scheme to support high-capacity disk sizes. Consult the manufacturer for accurate drive specifications.
        /// Example: 657
        /// </summary>
        public Nullable<UInt64> TotalCylinders { get { return _TotalCylinders; } }

        /// <summary>
        /// Total number of heads on the disk drive. Note: the value for this property is obtained through extended functions of BIOS interrupt 13h. The value may be inaccurate if the drive uses a translation scheme to support high-capacity disk sizes. Consult the manufacturer for accurate drive specifications.
        /// </summary>
        public Nullable<UInt32> TotalHeads { get { return _TotalHeads; } }

        /// <summary>
        /// Total number of sectors on the physical disk drive. Note: the value for this property is obtained through extended functions of BIOS interrupt 13h. The value may be inaccurate if the drive uses a translation scheme to support high-capacity disk sizes. Consult the manufacturer for accurate drive specifications.
        /// Example: 2649024
        /// </summary>
        public Nullable<UInt64> TotalSectors { get { return _TotalSectors; } }

        /// <summary>
        /// Total number of tracks on the physical disk drive. Note: the value for this property is obtained through extended functions of BIOS interrupt 13h. The value may be inaccurate if the drive uses a translation scheme to support high-capacity disk sizes. Consult the manufacturer for accurate drive specifications.
        /// Example: 42048
        /// </summary>
        public Nullable<UInt64> TotalTracks { get { return _TotalTracks; } }

        /// <summary>
        /// Number of tracks in each cylinder on the physical disk drive. Note: the value for this property is obtained through extended functions of BIOS interrupt 13h. The value may be inaccurate if the drive uses a translation scheme to support high-capacity disk sizes. Consult the manufacturer for accurate drive specifications.
        /// Example: 64
        /// </summary>
        public Nullable<UInt32> TracksPerCylinder { get { return _TracksPerCylinder; } }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mbo"></param>
        public Win32_DiskDrive(ManagementBaseObject mbo)
            : base(mbo)
        {
            _BytesPerSector = mbo.GetUIntValue("BytesPerSector");
            _FirmwareRevision = mbo.GetStringValue("FirmwareRevision");
            _Index = mbo.GetUIntValue("Index");
            _InterfaceType = mbo.GetStringValue("InterfaceType");
            _Manufacturer = mbo.GetStringValue("Manufacturer");
            _MediaLoaded = mbo.GetBoolValue("MediaLoaded");
            _MediaType = mbo.GetStringValue("MediaType");
            _Model = mbo.GetStringValue("Model");
            _Partitions = mbo.GetUIntValue("Partitions");
            _SCSIBus = mbo.GetUIntValue("SCSIBus");
            _SCSILogicalUnit = mbo.GetUshortValue("SCSILogicalUnit");
            _SCSIPort = mbo.GetUshortValue("SCSIPort");
            _SCSITargetId = mbo.GetUshortValue("SCSITargetId");
            _SectorsPerTrack = mbo.GetUIntValue("SectorsPerTrack");
            _SerialNumber = mbo.GetStringValue("SerialNumber");
            _Signature = mbo.GetUIntValue("Signature");
            _Size = mbo.GetUlongValue("Size");
            _TotalCylinders = mbo.GetUlongValue("TotalCylinders");
            _TotalHeads = mbo.GetUIntValue("TotalHeads");
            _TotalSectors = mbo.GetUlongValue("TotalSectors");
            _TotalTracks = mbo.GetUlongValue("TotalTracks");
            _TracksPerCylinder = mbo.GetUIntValue("TracksPerCylinder");
        }

    }



    /// <summary>
    /// 
    /// </summary>
    public class GetWin32_DiskDrives : Win32Collection<Win32_DiskDrive>
    {

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override ReadOnlyCollection<Win32_DiskDrive> GetCollection()
        {
            List<Win32_DiskDrive> tempCollection = new List<Win32_DiskDrive>();

            foreach (var s in searcher.Get())
            {
                Win32_DiskDrive tempListItem = new Win32_DiskDrive(s);
                tempCollection.Add(tempListItem);
            }

            return tempCollection.AsReadOnly();
        }

        /// <summary>
        /// 
        /// </summary>
        public GetWin32_DiskDrives() : base("SELECT * FROM Win32_DiskDrive") { }

    }

}
